import tourEventEnum from "../enum/tourEvent.enum"
import { GetTourDataCommand } from "../command/tour.command"
import SdkCommand from "../command/sdk.command"
import { ClassFactory, DependencyFetcher, isNum } from "./utils"
import Logger from "../utils/Logger"
import ToursControlsModule from "../module/ToursControlsModule"
import TourData from "../data/TourData"
class TourStartExecutor {
  validateInput(e) {
    const log = new Logger("sdk: tours")
    void 0 !== e.index && isNaN(e.index) && (log.warn(e.index, "is not a valid number"), (e.index = void 0))
    void 0 !== e.steps && isNaN(e.steps) && (log.warn(e.steps, "is not a valid number"), (e.steps = void 0))
    return e
  }
  exec(e, t, o, n) {
    if (0 === n.getSnapshotCount()) throw Error("No tour data found")
    if (!o.canChangeTourLocation()) throw Error("TourStart ignored, cannot change location at this time, another transition is active")
    try {
      o.startTour(e.index, e.steps, e.loop), t.return()
    } catch (e) {
      t.throw(`Error occurred while starting tour - ${e}`)
    }
  }
}
class TourStopExecutor {
  validateInput(e) {
    return e
  }
  exec(e, t, o) {
    o.stopTour()
      .then(() => t.return())
      .catch(e => {
        t.throw(`Error occurred while stopping tour - ${e}`)
      })
  }
}
class TourStepExecutor {
  validateInput(e, t, o) {
    const n = e.index
    if (!isNum(n)) throw Error(n + " is not a valid tour snapshot index")
    if (n < 0 || n > o.getSnapshotCount()) throw Error(`${n} is outside of the range of tour snapshots: [0 , ${o.getSnapshotCount() - 1}]`)
    return { index: n }
  }
  exec(e, t, o, n) {
    if (0 === n.getSnapshotCount()) throw Error("No tour data found")
    if (!o.canChangeTourLocation()) throw Error("TourStep ignored, cannot change location at this time, another transition is active")
    o.tourGoTo(e.index)
      .then(() => t.return())
      .catch(e => {
        t.throw(`Error occurred while jumping to new tour location - ${e}`)
      })
  }
}
class TourStepRelativeExecutor {
  forward: any
  constructor(e) {
    this.forward = e
  }
  validateInput(e) {
    return e
  }
  exec(e, t, o, n) {
    if (0 === n.getSnapshotCount()) throw Error("No tour data found")
    if (!o.canChangeTourLocation()) throw Error("TourStep ignored, cannot change location at this time, another transition is active")
    ;(this.forward ? o.tourGoNext(!1) : o.tourGoPrevious(!1))
      .then(() => t.return())
      .catch(e => {
        t.throw(`Error while trying to travel to the next tour snapshot - ${e}`)
      })
  }
}
export default {
  Event: sdk => sdk.addEnumToInterface({ namespace: "Tour", name: "Event", values: tourEventEnum }),
  onEvent: (sdk, exportOBJ, allFunc) => {
    allFunc.subscribe(exportOBJ.TourStartedMessage, () => sdk.broadcast(tourEventEnum.STARTED))
    allFunc.subscribe(exportOBJ.TourStoppedMessage, () => sdk.broadcast(tourEventEnum.STOPPED))
    allFunc.subscribe(exportOBJ.TourEndedMessage, () => sdk.broadcast(tourEventEnum.ENDED))
    const n = [-1],
      r = e => ((n[0] = e.index), n)
    allFunc.subscribe(exportOBJ.TourSteppedMessage, t => sdk.broadcast(tourEventEnum.STEPPED, r, t))
  },
  getData: (sdk, exportOBJ, allFunc, dependencies: DependencyFetcher<[Promise<ToursControlsModule>, Promise<TourData>]>) => {
    allFunc.addBinding(GetTourDataCommand, async () =>
      dependencies.getDependencies().then(async ([o, n]) => {
        const r = await Promise.all(
          n.getEnabledSnapshots().map(snapshots =>
            (async (snapshots, exportOBJ, allFunc) => {
              let mode = allFunc.viewmodeConverter.toSdk(snapshots.metadata.cameraMode)
              if (!mode || mode === allFunc.commandModeConverter.toSdk(exportOBJ.CommandViewmode.TRANSITIONING))
                throw Error("Failed to convert snapshot, invalid viewmode")
              mode === allFunc.commandModeConverter.toSdk(exportOBJ.CommandViewmode.INSIDE) &&
                snapshots.is360 &&
                (mode = allFunc.commandModeConverter.toSdk(exportOBJ.CommandViewmode.OUTSIDE))
              return {
                sid: snapshots.sid,
                thumbnailUrl: await snapshots.thumbnailUrl.get(),
                imageUrl: await snapshots.imageUrl.get(),
                is360: snapshots.is360,
                name: snapshots.name,
                mode,
                zoom: snapshots.metadata.ssZoom,
                position: snapshots.metadata.cameraPosition,
                rotation: allFunc.conversionUtils.quaternionToRotation(snapshots.metadata.cameraQuaternion)
              }
            })(snapshots, exportOBJ, allFunc)
          )
        )
        if (!r.length) throw Error("No tour data found")
        return r
      })
    )
    sdk.addCommandCreator({ namespace: "Tour", name: "getData", args: [] }, () => new GetTourDataCommand())
  },
  start: (sdk, dependencies) => {
    const a = SdkCommand.create(dependencies, new ClassFactory(TourStartExecutor))
    sdk.addCommandToInterface({ namespace: "Tour", name: "start", args: ["index"] }, a)
  },
  stop: (sdk, dependencies) => {
    const a = SdkCommand.create(dependencies, new ClassFactory(TourStopExecutor))
    sdk.addCommandToInterface({ namespace: "Tour", name: "stop", args: [] }, a)
  },
  step: (sdk, dependencies) => {
    const a = SdkCommand.create(dependencies, new ClassFactory(TourStepExecutor))
    sdk.addCommandToInterface({ namespace: "Tour", name: "step", args: ["index"] }, a)
  },
  prev: (sdk, dependencies) => {
    const a = SdkCommand.create(dependencies, new ClassFactory(TourStepRelativeExecutor, !0))
    sdk.addCommandToInterface({ namespace: "Tour", name: "prev", args: [] }, a)
  },
  next: (sdk, dependencies) => {
    const a = SdkCommand.create(dependencies, new ClassFactory(TourStepRelativeExecutor, !1))
    sdk.addCommandToInterface({ namespace: "Tour", name: "next", args: [] }, a)
  }
}
